package org.lds.scheduled.job.admin.business.job.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.BooleanUtils;
import org.lds.scheduled.job.admin.business.app.entity.App;
import org.lds.scheduled.job.admin.business.app.mapper.AppMapper;
import org.lds.scheduled.job.admin.business.appinstance.entity.AppInstance;
import org.lds.scheduled.job.admin.business.appinstance.mapper.AppInstanceMapper;
import org.lds.scheduled.job.admin.business.job.entity.Job;
import org.lds.scheduled.job.admin.business.job.mapper.JobMapper;
import org.lds.scheduled.job.admin.business.job.model.request.JobBaseCreateRequest;
import org.lds.scheduled.job.admin.business.job.model.request.JobBaseGetByKeyRequest;
import org.lds.scheduled.job.admin.business.job.model.request.JobBaseUpdateRequest;
import org.lds.scheduled.job.admin.business.job.model.response.JobBaseResponse;
import org.lds.scheduled.job.admin.business.job.service.JobBaseService;
import org.lds.scheduled.job.admin.business.job.service.JobService;
import org.lds.scheduled.job.admin.client.core.model.request.RegisterJobRequest;
import org.lds.scheduled.job.admin.client.core.model.response.RegisterJobResponse;
import org.lds.scheduled.job.common.constant.CommonConstant;
import org.lds.scheduled.job.common.model.ScheduledJobModel;
import org.lds.scheduled.job.common.model.dto.ResultDTO;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 服务实现类
 *
 * @author lidongsheng
 * @since 2025-01-16
 */
@RequiredArgsConstructor
@Service
public class JobServiceImpl extends ServiceImpl<JobMapper, Job> implements JobService {
    private final AppMapper appMapper;
    private final AppInstanceMapper appInstanceMapper;
    private final JobBaseService jobBaseService;

    @Override
    public ResultDTO<RegisterJobResponse> registerJob(RegisterJobRequest request) {
        Long appId = saveOrUpdateApp(request.getAppName());
        Long appInstanceId = saveOrUpdateAppInstance(appId, request.getAppInstanceIp(), request.getAppInstancePort());

        List<RegisterJobResponse.Job> jobs = new ArrayList<>();
        for (ScheduledJobModel scheduledJobModel : request.getScheduledJobModels()) {
            Long jobId = saveOrUpdateJob(appId, scheduledJobModel);

            jobs.add(RegisterJobResponse.Job.builder()
                            .name(scheduledJobModel.getKey())
                            .id(jobId)
                            .triggerRuleType(scheduledJobModel.getTriggerRuleType())
                            .triggerRuleContent(scheduledJobModel.getTriggerRuleContent())
                    .build());
        }

        return ResultDTO.success(RegisterJobResponse.builder()
                        .appId(appId)
                        .appInstanceId(appInstanceId)
                        .jobs(jobs)
                        .build());
    }

    private Long saveOrUpdateApp(String appName) {
        App app = appMapper.selectOne(new QueryWrapper<>(App.builder().name(appName).build()));
        if (Objects.nonNull(app)) {
            if (BooleanUtils.isFalse(app.getEnable())) {
                appMapper.updateById(App.builder()
                                .id(app.getId())
                                .enable(true)
                                .modifier(CommonConstant.DEFAULT_USER)
                                .updateTime(LocalDateTime.now())
                                .build());
            }
            return app.getId();
        } else {
            LocalDateTime now = LocalDateTime.now();
            App newApp = App.builder()
                    .name(appName)
                    .creator(CommonConstant.DEFAULT_USER)
                    .modifier(CommonConstant.DEFAULT_USER)
                    .createTime(now)
                    .updateTime(now)
                    .build();
            appMapper.insert(newApp);
            return newApp.getId();
        }
    }

    private Long saveOrUpdateAppInstance(Long appId, String ip, Integer port) {
        AppInstance appInstance = appInstanceMapper.selectOne(new QueryWrapper<>(AppInstance.builder().appId(appId).ip(ip).port(port).build()));
        if (Objects.nonNull(appInstance)) {
            if (BooleanUtils.isFalse(appInstance.getEnable())) {
                appInstanceMapper.updateById(AppInstance.builder()
                        .id(appInstance.getId())
                        .enable(true)
                        .modifier(CommonConstant.DEFAULT_USER)
                        .updateTime(LocalDateTime.now())
                        .build());
            }
            return appInstance.getId();
        } else {
            LocalDateTime now = LocalDateTime.now();
            AppInstance newAppInstance = AppInstance.builder()
                    .appId(appId)
                    .ip(ip)
                    .port(port)
                    .creator(CommonConstant.DEFAULT_USER)
                    .modifier(CommonConstant.DEFAULT_USER)
                    .createTime(now)
                    .updateTime(now)
                    .build();
            appInstanceMapper.insert(newAppInstance);
            return newAppInstance.getId();
        }
    }

    private Long saveOrUpdateJob(Long appId, ScheduledJobModel scheduledJobModel) {
        Job job = jobBaseService.getJobByKey(
                JobBaseGetByKeyRequest.builder()
                        .appId(appId)
                        .name(scheduledJobModel.getKey())
                        .build());
        if (Objects.nonNull(job)) {
            if (BooleanUtils.isFalse(job.getEnable())) {
                jobBaseService.updateJob(
                        JobBaseUpdateRequest.builder()
                                .id(job.getId())
                                .enable(true)
                                .build());
            }
            return job.getId();
        } else {
            ResultDTO<JobBaseResponse> resultDTO = jobBaseService.createJob(
                    JobBaseCreateRequest.builder()
                            .name(scheduledJobModel.getKey())
                            .appId(appId)
                            .triggerRuleType(scheduledJobModel.getTriggerRuleType())
                            .triggerRuleContent(scheduledJobModel.getTriggerRuleContent())
                            .build());
            return resultDTO.getData().getId();
        }
    }

}
